#include <vulkan/vulkan_core.h>
#include "DxvkShaderConstData.h"

DxvkShaderConstData::DxvkShaderConstData() {

}


DxvkShaderConstData::DxvkShaderConstData(
    size_t                dwordCount,
    const uint32_t* dwordArray)
    : m_size(dwordCount), m_data(new uint32_t[dwordCount]) {
    for (size_t i = 0; i < dwordCount; i++)
        m_data[i] = dwordArray[i];
}


DxvkShaderConstData::DxvkShaderConstData(DxvkShaderConstData&& other)
    : m_size(other.m_size), m_data(other.m_data) {
    other.m_size = 0;
    other.m_data = nullptr;
}


DxvkShaderConstData& DxvkShaderConstData::operator = (DxvkShaderConstData&& other) {
    delete[] m_data;
    this->m_size = other.m_size;
    this->m_data = other.m_data;
    other.m_size = 0;
    other.m_data = nullptr;
    return *this;
}


DxvkShaderConstData::~DxvkShaderConstData() {
    delete[] m_data;
}

uint32_t DxvkBindingInfo::computeSetIndex() const {
    if (stage == VK_SHADER_STAGE_COMPUTE_BIT) {
        // Use one single set for compute shaders
        return DxvkDescriptorSets::CsAll;
    }
    else if (stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
        // For fragment shaders, create a separate set for UBOs
        return uboSet
            ? DxvkDescriptorSets::FsBuffers
            : DxvkDescriptorSets::FsViews;
    }
    else {
        // Put all vertex shader resources into the last set.
        // Vertex shader UBOs are usually updated every draw,
        // and other resource types are rarely used.
        return DxvkDescriptorSets::VsAll;
    }
}


uint32_t DxvkBindingInfo::value() const {
    return (uint32_t(descriptorType) << 24) | resourceBinding;
}


bool DxvkBindingInfo::eq(const DxvkBindingInfo& other) const {
    return descriptorType == other.descriptorType
        && resourceBinding == other.resourceBinding
        && viewType == other.viewType
        && stage == other.stage
        && access == other.access
        && uboSet == other.uboSet;
}

class DxvkHashState {

public:

    void add(size_t hash) {
        m_value ^= hash + 0x9e3779b9
            + (m_value << 6)
            + (m_value >> 2);
    }

    operator size_t () const {
        return m_value;
    }

private:

    size_t m_value = 0;

};

size_t DxvkBindingInfo::hash() const {
    DxvkHashState hash;
    hash.add(uint32_t(descriptorType));
    hash.add(resourceBinding);
    hash.add(uint32_t(viewType));
    hash.add(uint32_t(stage));
    hash.add(access);
    hash.add(uint32_t(uboSet));
    return hash;
}